defmodule IocpMonitor.LittleEndian do
  @moduledoc """
  Little endian的byte list和整数相互转换

  ## 示例

      iex> IocpMonitor.LittleEndian.to_i([1, 2, 3, 4])
      67305985

      iex> IocpMonitor.LittleEndian.to_bytes(16909060)
      [4, 3, 2, 1]
  
  """

  @type little_endian() :: list(integer())

  use Bitwise

  @doc """
  Little endian byte list转整数
  """
  @spec to_i(little_endian()) :: integer()
  def to_i(list) when is_list(list) do
    to_i(list, 0, 0)
  end

  defp to_i([h|t], offset, acc) do
    to_i(t, offset + 8, acc ||| (h <<< offset))
  end

  defp to_i([], _, acc), do: acc

  @doc """
  整数转little endian byte list
  """
  @spec to_bytes(integer()) :: little_endian()
  def to_bytes(n, octets \\ 2) when is_integer(n) do
    to_bytes(n, octets, [])
  end

  defp to_bytes(0, octets, acc) do
    acc
    |> padding(octets)
    |> Enum.reverse()
  end

  defp to_bytes(n, octets, acc) do
    to_bytes(n >>> 8, octets, [n &&& 0xFF | acc])
  end

  defp padding(bytes, octets) when length(bytes) >= octets, do: bytes

  defp padding(bytes, _octets) do
    [0 | bytes]
  end
end
